package com.hzw.saas.service.rbac.service;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.rbac.IPermissionService;
import com.hzw.saas.api.rbac.IUserRoleService;
import com.hzw.saas.api.rbac.bo.PermissionTreeBO;
import com.hzw.saas.api.rbac.bo.RoleBO;
import com.hzw.saas.api.rbac.constants.RbacConsts;
import com.hzw.saas.api.rbac.enums.PermSysEnum;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.service.rbac.config.RbacConfig;
import com.hzw.saas.service.rbac.mapper.UserRoleMapper;
import com.hzw.saas.service.rbac.model.Permission;
import com.hzw.saas.service.rbac.model.Role;
import com.hzw.saas.service.rbac.model.UserRole;
import com.hzw.saas.service.rbac.util.RbacUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.StrSplitter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zzl
 * @since 08/31/2021
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements IUserRoleService, IService<UserRole> {

    private final RbacConfig rbacConfig;

    @Resource
    private IPermissionService permissionService;

    @Override
    public boolean deleteRole(String roleId) {
        return super.lambdaUpdate().eq(UserRole::getRoleId, roleId).remove();
    }

    @Override
    public boolean deleteRoles(List<String> roleIds) {
        if (CollectionUtil.isEmpty(roleIds))
            return true;
        return super.lambdaUpdate().in(UserRole::getRoleId, roleIds).remove();
    }

    @Override
    public boolean deleteUser(Integer system, String userId) {
        return super.lambdaUpdate()
            .eq(UserRole::getSys, system)
            .eq(UserRole::getUserId, userId)
            .remove();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserRole(Integer sys, String userId, List<String> roleIds) {
        if (ObjectUtil.hasNull(sys, userId, roleIds))
            return false;
        PermSysEnum.assertValid(sys);
        // 删除原用户角色关联
        super.lambdaUpdate()
            .eq(UserRole::getSys, sys)
            .eq(UserRole::getUserId, userId)
            .remove();
        // 创建新的用户角色关联
        if (roleIds.isEmpty())
            return true;
        List<UserRole> entities = new ArrayList<>();
        for (String roleId : roleIds) {
            entities.add(new UserRole(sys, userId, roleId));
        }
        super.saveBatch(entities);
        return true;
    }

    @Override
    public List<RoleBO> listRoles(Integer sys, String userId) {
        List<Role> roles = super.baseMapper.listRoles(sys, userId);
        return MapperUtil.nf().mapAsList(roles, RoleBO.class);
    }

    @Override
    public List<String> listRoleIds(Integer sys, String userId) {
        List<UserRole> userRoles = super.lambdaQuery()
            .eq(UserRole::getSys, sys)
            .eq(UserRole::getUserId, userId)
            .orderByAsc(UserRole::getRoleId)
            .list();
        return userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
    }

    @Override
    public List<PermissionTreeBO> listPermTrees(Integer sys, String userId, String supId, Integer level, Integer... types) {
        supId = StrUtil.isBlank(supId) ? RbacConsts.ROOT_PERMISSION_SUP_ID : supId;
        if (rbacConfig.isSuperAdmin(userId)) {
            return permissionService.listTree(sys, supId, level, types);
        }
        List<Permission> entities = super.baseMapper.listPermissions(sys, userId, ListUtil.toList(types));
        List<PermissionTreeBO> sources = MapperUtil.nf().mapAsList(entities, PermissionTreeBO.class);
        RbacUtil.assemblePermissionText(sources);
        return RbacUtil.assemblePermissionTrees(sources, supId, level);
    }

    @Override
    public List<String> listPermissionIds(Integer sys, String userId) {
        return super.baseMapper.listPermissionIds(sys, userId);
    }

    @Override
    public List<String> listAuthorities(Integer sys, String userId) {
        Set<String> authorities = new LinkedHashSet<>();
        List<String> authStrList = super.baseMapper.listAuthorities(sys, userId);
        for (String authStr : authStrList) {
            List<String> split = StrSplitter.split(authStr, RbacConsts.AUTHORITY_DELIMITER, true, true);
            authorities.addAll(split);
        }
        return ListUtil.toList(authorities);
    }
}
